

#define _CRT_SECURE_NO_WARNINGS
#include "Socket.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include "Tools.h"

CSocket::CSocket()
{
        this->m_sock = (SOCKET)(INVALID_SOCKET);
        this->m_eSockType = eSocketType_TCP;
        m_bListening = false;
        m_host.sin_family       = AF_INET;
        m_host.sin_addr.s_addr  = INADDR_ANY;
        m_host.sin_port         = 0;
        m_remote.sin_family     = AF_INET;
        m_remote.sin_addr.s_addr= INADDR_ANY;
        m_remote.sin_port       = 0;
        m_LastActiveTime        = 0;
}

CSocket::CSocket(SOCKETTYPE eSocketType)
{
        this->m_sock = (SOCKET)(INVALID_SOCKET);
        this->m_eSockType = eSocketType;
        memset(&m_remote, 0, sizeof(sockaddr_in));
        memset(&m_host, 0, sizeof(sockaddr_in));
        m_bListening = false;
        m_host.sin_family       = AF_INET;
        m_host.sin_addr.s_addr  = INADDR_ANY;
        m_host.sin_port         = 0;
        m_remote.sin_family     = AF_INET;
        m_remote.sin_addr.s_addr= INADDR_ANY;
        m_remote.sin_port       = 0;
        m_LastActiveTime        = 0;
}

CSocket::~CSocket()
{
        Close();
}

void CSocket::Create(void)
{
        Close();
        if(m_eSockType == eSocketType_TCP)
                m_sock = socket(PF_INET, SOCK_STREAM, 0);
        else if(m_eSockType == eSocketType_UDP)
                m_sock = socket(PF_INET, SOCK_DGRAM, 0);
        else if(m_eSockType == eSocketType_Console)
                m_sock = 0;
        if(m_sock == (SOCKET)(SOCKET_ERROR) || m_sock == (SOCKET)(INVALID_SOCKET))
        {
                throw("socket() error.");
        }
}

SOCKET CSocket::GetSocket(void)
{
        return m_sock;
}

const char * CSocket::GetRemoteIP(void)
{
        return static_cast<const char *>(inet_ntoa(m_remote.sin_addr));
}

void CSocket::SetRemoteIP(const char * ipaddr)
{
        m_remote.sin_addr.s_addr = inet_addr(ipaddr);
}

int CSocket::GetRemotePort(void)
{
        return static_cast<int>(ntohs(m_remote.sin_port));
}

void CSocket::SetRemotePort(int port)
{
        m_remote.sin_port = htons(port);
}

const char * CSocket::GetHostIP(void)
{
        return static_cast<const char *>(inet_ntoa(m_host.sin_addr));
}

void CSocket::SetHostIP(const char * ipaddr)
{
        if(m_bListening)
                throw("cannot set host ip.");
        m_host.sin_addr.s_addr = inet_addr(ipaddr);
}

int CSocket::GetHostPort(void)
{
        return static_cast<int>(ntohs(m_host.sin_port));
}

void CSocket::SetHostPort(int port)
{
        if(m_bListening)
                throw("cannot set host port.");
        m_host.sin_port = htons(port);
}

void CSocket::SetBroadCast(bool bBroad)
{
        int     onoff = 0;
        if(bBroad)
                onoff = 1;
        if( 0 != setsockopt(m_sock, SOL_SOCKET, SO_BROADCAST, (char *)&onoff, sizeof(int)) )
        {
                throw(DisplayError("setsockopt"));
        }
}

void CSocket::Listen(void)
{
        if(listen(m_sock, 10) != 0)
        {
                throw(DisplayError("listen"));
        }
}

void CSocket::Bind(int port)
{
        if(port != -1)
                SetHostPort(port);

        int             opt = 1;
        socklen_t       len = sizeof(opt);
        if(setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, len) != 0)
        {
                DisplayError("setsockopt.SO_REUSEADDR");
        }

        PRINTF("bind to: %s:%d\n", GetHostIP(), GetHostPort());
        if(bind(m_sock, (struct sockaddr *)&m_host, sizeof(m_host)) != 0)
        {
                throw(DisplayError("bind"));
        }
}

void CSocket::Connect(const char * ipaddr, int port)
{
        if(ipaddr != NULL)
                SetRemoteIP(ipaddr);
        if(port != -1)
                SetRemotePort(port);
        PRINTF("connect to %s:%d\n", GetRemoteIP(), GetRemotePort());
        if(connect(m_sock, (struct sockaddr *)&m_remote, sizeof(m_remote)) != 0)
        {
                throw(DisplayError("connect"));
        }
}

void CSocket::Accept(CSocket& sock)
{
        socklen_t       len;
        SOCKET          fd;
        len = sizeof(m_remote);
        fd = accept(m_sock, (struct sockaddr *)&m_remote, &len);
        PRINTF("accept: %s:%d\n", GetRemoteIP(), GetRemotePort());
        sock.Close();
        sock.m_sock = fd;
        sock.SetRemoteIP(GetRemoteIP());
        sock.SetRemotePort(GetRemotePort());
}

int CSocket::Recv(void * buf, size_t len)
{
        socklen_t       sl;
        int             ret;
        sl = sizeof(m_remote);
        if(m_eSockType == eSocketType_TCP)
        {
                ret = recv(m_sock, (char *)buf, len, 0);
        }
        else if(m_eSockType == eSocketType_UDP)
        {
                ret = recvfrom(m_sock, (char *)buf, len, 0, (struct sockaddr *)&m_remote, &sl);
        }
        else
        {
#if defined(WIN32) || defined(_WIN32)
                ret = recv(m_sock, (char *)buf, len, 0);
#else
                ret = read(m_sock, (char *)buf, len);
#endif
        }
        if(ret <= 0)
                OnRemoteDown();
        else
                OnReadData(buf, ret);
        return ret;
}

int CSocket::Send(const void * buf, size_t len)
{
        socklen_t       sl;
        sl = sizeof(m_remote);

        if(m_eSockType == eSocketType_TCP)
                return send(m_sock, (const char *)buf, len, 0);
        else if(m_eSockType == eSocketType_UDP)
                return sendto(m_sock, (const char *)buf, len, 0, (struct sockaddr *)&m_remote, sl);
        else 
        {
#if defined(WIN32) || defined(_WIN32)
                return send(m_sock, (const char *)buf, len, 0);
#else
                return write(m_sock, (const char *)buf, len);
#endif
        }

}

int CSocket::RecvFrom(char * ipaddr, int& port, void * buf, size_t len)
{
        int             ret;
        ret = Recv(buf, len);
        strcpy(ipaddr, GetRemoteIP());
        port = GetRemotePort();
        return ret;
}

int CSocket::SendTo(const char * ipaddr, int port, const void * buf, size_t len)
{
        SetRemoteIP(ipaddr);
        SetRemotePort(port);
        return Send(buf, len);
}

void CSocket::Close()
{
        if(m_sock == (SOCKET)INVALID_SOCKET || m_sock == (SOCKET)SOCKET_ERROR)
                return;
        closesocket(m_sock);
        m_sock                  = (SOCKET)(INVALID_SOCKET);
        m_bListening            = false;
        m_eSockType             = eSocketType_TCP;
        m_host.sin_family       = AF_INET;
        m_host.sin_addr.s_addr  = INADDR_ANY;
        m_host.sin_port         = 0;
        m_remote.sin_family     = AF_INET;
        m_remote.sin_addr.s_addr= INADDR_ANY;
        m_remote.sin_port       = 0;
        m_LastActiveTime        = 0;
}

void CSocket::SetLastActiveTime(void)
{
        m_LastActiveTime = time(NULL);
}

time_t CSocket::GetLastActiveTime(void)
{
        return m_LastActiveTime;
}

void CSocket::OnReadData(const void * buf, int len)
{
}

const char * CSocket::DisplayError(const char * str)
{
#if defined(WIN32) || defined(_WIN32)
        DWORD dw = WSAGetLastError();
        LPVOID  lpMsgBuf;
        static TCHAR   buff[1024];
        FormatMessageA(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dw,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                (LPSTR) &lpMsgBuf,
                0,
                NULL
                );
        printf("[WIN32]%s:error %lu, %s\n", str, dw, (char *)lpMsgBuf);
        fflush(stdout);
        lstrcpy(buff, (LPCSTR)lpMsgBuf);
        LocalFree(lpMsgBuf);
        return buff;
#else
        perror(str);
        return strerror(errno);
#endif
}

void CSocket::OnRemoteDown(void)
{
}


